#!/usr/local/u-mail/app/engine/bin/python
# coding:utf-8

"""
wget http://update.comingchina.com:8080/testing/private/7/x86_64/umail_config-5.5.21-8.alpha.el7.x86_64.rpm
wget http://update.comingchina.com:8080/testing/private/7/x86_64/umail_app-2.3.18-1.alpha.el7.x86_64.rpm
yum install umail_config-5.5.21-8.alpha.el7.x86_64.rpm
yum install umail_app-2.3.18-1.alpha.el7.x86_64.rpm
"""
# import asyncore
from gevent import monkey;monkey.patch_all()
import socket, smtplib, gevent
from gsmtpd import SMTPServer
from dns.resolver import Resolver
import logging


logger = logging.getLogger('smtpProxy')
logger.setLevel(logging.INFO)
#handler = logging.handlers.SysLogHandler(address='/dev/log', facility="mail")
handler = logging.StreamHandler()
formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s","%Y%m%d %H:%M:%S")
handler.setFormatter(formatter)
logger.addHandler(handler)


def parse_mx_answer(domain):
    answer = Resolver().query(domain, "MX")
    hostmaps = []
    srv_list = []
    for item in answer.rrset:
        address = item.exchange.to_text()
        address = address[:-1]
        hostmaps.append((item.preference, address))

    for item in sorted(hostmaps):
        srv_list.append(item[1])

    return srv_list


def _deliver(mailfrom, rcpttos, data, _remoteaddr):
    refused = {}
    try:
        s = smtplib.SMTP()
        s.connect(_remoteaddr[0], _remoteaddr[1])
        logger.info("(%s:%s)" % (_remoteaddr[0], _remoteaddr[1]))
        # s.set_debuglevel(1)
        try:
            refused = s.sendmail(mailfrom, rcpttos, data)
        finally:
            s.quit()
    except smtplib.SMTPRecipientsRefused, e:
        logger.error('got SMTPRecipientsRefused <%s>--><%s>' % (mailfrom, rcpttos))
        refused = e.recipients
    except (socket.error, smtplib.SMTPException), e:
        logger.error('got %s' % (e.__class__))
        # print 'got', e.__class__
        # All recipients were refused.  If the exception had an associated
        # error code, use it.  Otherwise,fake it with a non-triggering
        # exception code.
        errcode = getattr(e, 'smtp_code', -1)
        errmsg = getattr(e, 'smtp_error', 'ignore')
        for r in rcpttos:
            refused[r] = (errcode, errmsg)
    return refused


def smtp_handle(peer, mailfrom, rcpttos, data):
    # lines = data.split('\n')
    # # Look for the last header
    # i = 0
    # for line in lines:
    #     if not line:
    #         break
    #     i += 1
    # lines.insert(i, 'X-Peer: %s' % peer[0])
    # data = NEWLINE.join(lines)
    # *******************************************************
    logger.info('Receiving message from: (%s:%s)' % peer)
    logger.info('Message addressed from: %s' % mailfrom)
    logger.info('Message addressed to  : %s' % rcpttos)
    logger.info('Message length        : %s' % len(data))
    # print data

    if "@josephrobinettebiden.top" not in mailfrom:
        logger.error("[ERROR] mailfrom:%s, no proxy smtp" % mailfrom)
        logger.error("*************NOTIFY*************")
        return

    for rcptto in rcpttos:
        # print rcptto
        if "@" not in rcptto:
            logger.error("error rcptto:%s" % rcptto)
            logger.error("*************NOTIFY*************")
            continue
        if len(rcptto.split("@")) != 2:
            logger.error("error rcptto:%s" % rcptto)
            continue
        domain = rcptto.split("@")[1]
        if "gmail.com" in domain:
            logger.error("gmail.com in domain")
            return
        if "qg.com" in domain:
            logger.error("qg.com in domain")
            return
        # print domain
        try:
            MXs = parse_mx_answer(domain)
        except:
            MXs = []
        if len(MXs) > 3:
            MXs = MXs[:3]
        logger.info("domain:(%s)--->MXs:[%s]" % (domain, ",".join(MXs)))
        for MX in MXs:
            if 'iphmx.com' in MX:
                logger.error("iphmx.com in MX")
                return
            if 'gmail.com' in MX:
                logger.error("gmail.com in MX")
                return
            _remoteaddr = (MX, 25)
            # *******************************************************
            refused = _deliver(mailfrom, rcpttos, data, _remoteaddr)
            if not refused:
                logger.info('Message addressed to %s success' % rcptto)
                return
            logger.error("***********we got some refusals***********")
            logger.error(refused)
            logger.error("***********we got some refusals***********")


class PureProxy(SMTPServer):
    def process_message(self, peer, mailfrom, rcpttos, data):
        gevent.spawn(smtp_handle, peer, mailfrom, rcpttos, data)
        # smtp_handle(peer, mailfrom, rcpttos, data)


server = PureProxy(('0.0.0.0', 465))
server.serve_forever()